#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os, sys
import filecmp
import json
from collections import defaultdict

"""
Find the different files which have same path and same file name.
"""


def compare_directory(dir1, dir2, show_files=False, show_common=False,
                      ignore_empty_dir=False, ignore_empty_file=False):
    stats = defaultdict(list)
    _compare_dir(dir1, dir2, stats)
    if parse_args(ignore_empty_dir):
        __process_ignore_empty_dir(stats)
    if parse_args(ignore_empty_file):
        __process_ignore_empty_file(stats)
    for k, v in stats.items():
        print("* %s files: %d" % (k, len(v)))
    if parse_args(show_files):
        print()
        for k, v in stats.items():
            if not parse_args(show_common) and k == 'common':
                continue
            print("** %s files ** \n%s\n" % (k, v))


def _compare_dir(dir1, dir2, stats):
    dir1, dir2 = [os.path.expanduser(d) for d in [dir1, dir2]]
    dir_comp = filecmp.dircmp(dir1, dir2)
    stats['left_only'].extend([os.path.join(dir1, f)
                               for f in dir_comp.left_only])
    stats['right_only'].extend([os.path.join(dir2, f)
                                for f in dir_comp.right_only])

    for item in dir_comp.common_files:
        f1, f2 = [os.path.join(d, item) for d in [dir1, dir2]]
        same_file = filecmp.cmp(f1, f2) or \
                    (item.endswith(".mnt.json") and compare_templates(f1, f2))
        stats['common' if same_file else "diff"].append((f1, f2))

    for item in dir_comp.common_dirs:
        d1, d2 = [os.path.join(d, item) for d in [dir1, dir2]]
        _compare_dir(d1, d2, stats)


def __process_ignore_empty_dir(stats):
    stats['left_only'] = [path for path in stats['left_only'] if
                          (os.path.isdir(path) and len(
                              os.listdir(path)) > 0) or os.path.isfile(
                              path)]
    stats['right_only'] = [path for path in stats['right_only'] if (
            os.path.isdir(path) and len(
        os.listdir(path)) > 0) or os.path.isfile(path)]


def __process_ignore_empty_file(stats):
    stats['left_only'] = [path for path in stats['left_only'] if
                          (os.path.isfile(path) and os.stat(
                              path).st_size > 0) or os.path.isdir(path)]
    stats['right_only'] = [path for path in stats['right_only'] if
                           os.path.isfile(path) and os.stat(
                               path).st_size > 0 or os.path.isdir(path)]


def ordered(obj):
    if isinstance(obj, dict):
        return sorted((k, ordered(v)) for k, v in obj.items())
    if isinstance(obj, list):
        return sorted(ordered(x) for x in obj)
    else:
        return obj


def compare_templates(fname1, fname2):
    fname1, fname2 = [os.path.expanduser(p) for p in [fname1, fname2]]
    with open(fname1) as f1:
        d1 = json.load(f1)
    with open(fname2) as f2:
        d2 = json.load(f2)
    return ordered(d1) == ordered(d2)


def parse_args(val):
    if isinstance(val, str):
        val = eval(val)
    return val


def main():
    if len(sys.argv) > 2:
        dir1 = sys.argv[1]
        dir2 = sys.argv[2]
    else:
        print("Usage:dir1 and dir2 can not be empty.")
        sys.exit()
    compare_directory(dir1, dir2)


if __name__ == '__main__':
    main()
